//                            _ooOoo_  
//                           o8888888o  
//                           88" . "88  
//                           (| -_- |)  
//                            O\ = /O  
//                        ____/`---'\____  
//                      .   ' \\| |// `.  
//                       / \\||| : |||// \  
//                     / _||||| -:- |||||- \  
//                       | | \\\ - /// | |  
//                     | \_| ''\---/'' | |  
//                      \ .-\__ `-` ___/-. /  
//                   ___`. .' /--.--\ `. . __  
//                ."" '< `.___\_<|>_/___.' >'"".  
//               | | : `- \`.;`\ _ /`;.`/ - ` : | |  
//                 \ \ `-. \_ __\ /__ _/ .-` / /  
//         ======`-.____`-.___\_____/___.-`____.-'======  
//                            `=---='  
//  
//         .............................................  
//                  佛祖保佑             永无BUG 
//          佛曰:  
//                  写字楼里写字间，写字间里程序员；  
//                  程序人员写程序，又拿程序换酒钱。  
//                  酒醒只在网上坐，酒醉还来网下眠；  
//                  酒醉酒醒日复日，网上网下年复年。  
//                  但愿老死电脑间，不愿鞠躬老板前；  
//                  奔驰宝马贵者趣，公交自行程序员。  
//                  别人笑我忒疯癫，我笑自己命太贱；  
//                  不见满街漂亮妹，哪个归得程序员？  


/* ****************************************************************************
 * Author: 671643387
 * Date: 2015/6/11
 * ***************************************************************************/

function AssistMine() {
    this.mines = {
        //uid:{
        //    local:{},
        //    global:{},
        //    count:0,
        //    time:0
        //}
    };

    this.updates = {};
    this.dirtyCount = 0;
}

AssistMine.create = function(){
    gDBWorld.insert({_id:"assist_mine",
        assist_mine:{
        }
    }, function(err, result){});
};

exports.AssistMine = AssistMine;

function getMineLevel(userLevel) {
    var mineLevel = 0;
    for (var level in gConfMineDistribute) {
        if (userLevel < level) break;
        mineLevel = level;
    }
    return mineLevel;
}

AssistMine.prototype = {
    init: function(fn){
        // 读取协助开矿数据
        gDBWorld.findOne({_id : 'assist_mine'}, {}, function(err, doc){
            if( doc ) {
                this.mines = doc.assist_mine;
            }
            fn();
        }.bind(this));
    },

    markDirty: function(uid, data){
        this.mines[uid] = data;
        this.updates[util.format('assist_mine.%d', uid)] = data;
        this.dirtyCount++;
    },

    save: function(force, fn){
        if (!force && (this.dirtyCount < 1)) {
            fn && fn(true);
        } else {
            var updates = this.updates;
            this.updates = {};
            this.dirtyCount = 0;

            gDBWorld.update({_id : 'assist_mine'}, {$set:updates}, true, function(err, result){
                if( err ) {
                    ERROR(util.format('SAVE ASSISTMINE: %j %j', updates, err));
                    fn && fn(false);
                }else {
                    LOG(util.format('SAVE ASSISTMINE: %j', updates));
                    fn && fn(true);
                }
            });
        }
    },

    _levelCheck: function(player) {
        return (player.user.status.level >= +gConfGlobal.AssistMineLevelLimit);
    },

    /**
     * 标记为可以协助
     * @param player    玩家
     * @param type      金矿类型(0/1)
     * @param id        金矿ID
     * @param pos       金矿位置
     * @param time      占矿时间
     */
    markMine: function(player, type, id, pos, time) {

        if (!this._levelCheck(player))
            return;

        var data = {
            id: id,
            pos: pos,
            time: time
        };

        var _uMine = this._getMineByUid(player.uid);

        // 更新金矿数据
        if (type == 0) {
            // 本服金矿
            _uMine.local = data;
            _uMine.localOutput = 1;
            _uMine.local_un = null;
        } else {
            // 跨服金矿
            _uMine.global = data;
            _uMine.globalOutput = 1;
            _uMine.global_un = null;
        }
        _uMine.mineLevel = getMineLevel(player.user.status.level);
        _uMine.time = Date.getStamp();

        this.markDirty(player.uid, _uMine);
        this.save();
    },

    /**
     * 取消可协助标记
     * @param uid
     * @param type
     * @param un
     */
    unMarkMine: function(uid, type, un) {
        // 玩家金矿
        var _uMine = this._getMineByUid(uid);

        if (type == 0) {
            _uMine.local = {};
            _uMine.local_un = un;
        } else {
            _uMine.global = {};
            _uMine.global_un = un;
        }

        this.markDirty(uid, _uMine);
        this.save();
    },

    /**
     * 获取数据
     * @param uid
     * @returns {{local: *, global: *}}
     */
    getByUid: function(uid) {
        return this._getMineByUid(uid);
    },

    /**
     * 获取好友的协助数据
     * @param player
     * @param fUid
     */
    getFriendMine: function(player, fUid) {
        var retRes = { global:{}, local:{} };

        do {
            var myMineLevel = getMineLevel(player.user.status.level);
            var _fMine = this._getMineByUid(fUid);
            var friendMineLevel = _fMine.mineLevel;

            // 玩家看不到好友的金矿
            if (myMineLevel != friendMineLevel) {
                break;
            }

            // 返回好友协助金矿数据
            retRes.local = _fMine.local;
            retRes.global = _fMine.global;
        } while (false);

        return retRes;
    },

    getMyCount: function(uid) {
        return this._getMineByUid(uid).count;
    },

    /**
     * 获取玩家金矿数据
     * @param uid
     * @private
     */
    _getMineByUid: function(uid){
        var _uMine = this.mines[uid] || {
                local:{},
                global:{},
                count:0,
                time:0,

                mineLevel:0,    // 玩家金矿等级

                localOutput:1,  // 本服金矿产量
                globalOutput:1,

                local_un: null,   // 本服金矿帮助者名字
                global_un: null   // 跨服金矿帮助者名字
            };

        var dirty = false;

        if (Date.getDayPassed(_uMine.time) != 1) { // 跨天，更新数据

            _uMine.count = 0;
            _uMine.time = Date.getStamp();

            dirty = true;
        }

        // 检查占矿时间，清除数据
        var now = common.getTime();
        var maxTime = gConfGlobal.MineOccupyTime * 3600;
        var mineTime = _uMine.local.time || 0;
        if ((mineTime != 0) && ((mineTime + maxTime) <= now)) {
            _uMine.local = {};
            _uMine.local_un = null;
            _uMine.localOutput = 1;

            dirty = true;
        }

        if (dirty) {
            this.markDirty(uid, _uMine);
            this.save();
        }

        return _uMine;
    },

    markOutput: function(uid, type) {
        var _uMine = this._getMineByUid(uid);
        if (type == 0) {
            _uMine.localOutput = 1 + (+gConfGlobal.AssistMineOutputFactor / 100);
        } else {
            _uMine.globalOutput = 1 + (+gConfGlobal.AssistMineOutputFactor / 100);
        }
        this.markDirty(uid, _uMine);
        this.save();
    },

    getOutput: function(uid, type){
        var _uMine = this._getMineByUid(uid);
        if (type == 0) {
            return _uMine.localOutput;
        } else {
            return _uMine.globalOutput;
        }
    },

    getAndResetOutput: function(uid, type) {
        var output = 1;
        var _uMine = this._getMineByUid(uid);
        if (type == 0) {
            output = _uMine.localOutput;
            _uMine.localOutput = 1;
        } else {
            output = _uMine.globalOutput;
            _uMine.globalOutput = 1;
        }
        this.markDirty(uid, _uMine);
        this.save();

        return output;
    },

    /**
     * 协助金矿战斗
     * @param player
     * @param fplayer
     * @param fUid
     * @param type  金矿类型(0/1)
     * @param mId   金矿ID
     * @param mPos  金矿POS
     * @param fn
     */
    battle: function(player, fplayer, fUid, type, mId, mPos, fn) {
        if (!gFriend.isFriend(fUid, player.uid)) {
            fn("you are not friends");
            return;
        }

        // 获取好友金矿协助数据
        var _uMine = this._getMineByUid(fUid);
        var fMine = (type == 0) ? _uMine.local : _uMine.global;
        if (!fMine || (mId != fMine.id || mPos != fMine.pos)) {
            // 玩家已经被援助或者参数错误
            fn("friend assist or parameter error");
            return;
        }

        var now = common.getTime();
        var maxTime = type == 0 ? gConfGlobal.MineOccupyTime * 3600: gConfGlobal.ServerMineOccupyTime * 3600;
        if ((fMine.time + maxTime) <= now) { // 占矿时间到了
            this.unMarkMine(fUid, type, null);

            fn("friend not own the mine");
            return;
        }

        var _mMine = this._getMineByUid(player.uid);
        _mMine.count += 1;
        this.markDirty(player.uid, _mMine);

        var ret = {};

        fplayer.roleImageInit();

        // 计算初始血量
        var factor = +gConfGlobal.AssistMineMonsterFactor / 100;
        var initHealth = Math.floor(fplayer.getRoleImageAttrCount("health") * factor);

        var attacker = new Fighter();
        var defender = new Fighter();
        attacker.initWithPlayer(player);
        defender.initWithAssistMineMonster(fplayer,
            roundIds(gConfAssistMineTeam, 1)[0], initHealth);

        var battleReport = attacker.fight(defender);
        var defRemainInfo = battleReport.def_remain_info;

        ret.battle = battleReport;

        // 计算怪物剩余血量
        var defRemainHealth = 0;
        for (var rid in defRemainInfo) {
            defRemainHealth += defRemainInfo[rid].health;
        }
        // 伤害血量百分比
        ret.hpAtkP = Math.ceil((battleReport.success ? 1 : (initHealth - defRemainHealth) / initHealth) * 100);

        // 怪物已经被干，取消标记
        this.unMarkMine(fUid, type, player.user.info.un);
        // 标记金矿增加产出
        this.markOutput(fUid, type);
        fn(null, ret);
    }
};